﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using D2DEngine.Components;
using Microsoft.Xna.Framework.Graphics;
using D2DEngine.Scene;

namespace D2DEngine
{
    public class D2DObject : IDisposable
    {
        protected bool isRegistered = false;
        protected bool isPoolable = false;

        protected string name;
        protected string type;
        protected List<D2DComponent> components = new List<D2DComponent>();

        /// <summary>
        /// Is the object registered ?
        /// </summary>
        public bool IsRegistered
        {
            get { return this.isRegistered; }
            set { this.isRegistered = value; }
        }

        /// <summary>
        /// Is the object poolable ?
        /// </summary>
        public bool IsPoolable
        {
            get { return this.isPoolable; }
            set { this.isPoolable = value; }
        }

        /// <summary>
        /// The object's unique name
        /// </summary>
        public string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }

        /// <summary>
        /// The object's type
        /// </summary>
        public string Type
        {
            get { return this.type; }
            set { this.type = value; }
        } 

        /// <summary>
        /// The components associated with this object
        /// </summary>
        public List<D2DComponent> Components
        {
            get { return this.components; }
        }

        public D2DObject()
        {
        }        

        /// <summary>
        /// Initializes the object.
        /// Object can now process
        /// </summary>
        public virtual void OnRegister()
        {
            if (!this.isRegistered)
            {
                this.isRegistered = true;

                foreach (D2DComponent component in this.components)
                {
                    component.OnRegister();
                }
            }
        }

        /// <summary>
        /// Uninitializes the object.
        /// Object can not process anymore
        /// </summary>
        public virtual void Dispose()
        {
            if (this.isRegistered)
            {
                this.isRegistered = false;
            }
        }

        /// <summary>
        /// Operations to execute when the object is unregistered
        /// </summary>
        public virtual void OnUnRegister()
        {
            // Unregister all components
            foreach (D2DComponent component in this.components)
            {
                component.OnUnRegister();
            }
        }

        /// <summary>
        /// Updates the object
        /// </summary>
        /// <param name="gameTime"></param>
        public virtual void Update(GameTime gameTime)
        {
            if (this.isRegistered)
            {
                // Update all components
                foreach (D2DComponent component in this.components)
                {
                    if (component.IsRegistered)
                        component.Update(gameTime);
                }
            }
        }

        /// <summary>
        /// Draws the object
        /// </summary>
        /// <param name="spriteBatch"></param>
        public virtual void Draw(SpriteBatch spriteBatch)
        {
            foreach (D2DComponent component in this.components)
            {
                component.Draw(spriteBatch);
            }
        }


        /// <summary>
        /// Adds a component to the object
        /// </summary>
        /// <param name="component"></param>
        public void AddComponent(D2DComponent component)
        {
            component.Owner = this;
            this.components.Add(component);

            if (this.isRegistered)
                component.OnRegister();
        }

        /// <summary>
        /// Retrieves a component of specified type.
        /// </summary>
        /// <typeparam name="T">Type of component</typeparam>
        /// <returns></returns>
        public T GetComponent<T>() where T : D2DComponent
        {
            T local = default(T);

            foreach (D2DComponent component in this.components)
            {
                local = component as T;
                if (local != null)
                {
                    return local;
                }
            }

            return default(T);
        }

        /// <summary>
        /// Clones the object
        /// </summary>
        /// <returns></returns>
        public object Clone()
        {
            D2DObject obj = (D2DObject)Activator.CreateInstance(this.GetType());

            CopyTo(obj);

            return obj;
        }

        /// <summary>
        /// Copies the object's properties to 
        /// another object
        /// </summary>
        /// <param name="obj"></param>
        protected virtual void CopyTo(D2DObject obj)
        {
            obj.Name = this.name;
            obj.Type = this.type;

            // Clear the components
            obj.Components.Clear();

            // Clone components
            foreach (D2DComponent comp in this.components)
            {
                obj.AddComponent((D2DComponent)comp.Clone());
            }
        }
    }
}
